#define FLIP_TEXTURE_Y 0

/*****************Utility Functions*************************/
float2 get_corrected_texture_coordinate(float2 textureCoordinate)
{
	#if FLIP_TEXTURE_Y
		return float2(textureCoordinate.x,1.0 - textureCoordinate.y);
	#else
		return textureCoordinate;
	#endif
}

float4 get_color_contribution(float4 contributingColor, float4 surfaceColor)
{
	//Color (.rbg) * Intensity (.a)
	return float4(contributingColor.rgb * contributingColor.a, 1.0f) * surfaceColor;
}

float get_fog_amount(float3 eyePosition, float4 worldPosition,float fogStart,float fogEnd)
{
	return saturate((length(eyePosition - worldPosition) - fogStart) / (fogEnd - fogStart));
	//saturate is use to clamp negative values for when the eye is closer than fog start
}

float3 apply_fog(float3 FogColor,float3 surfaceColor,float fogAmount)
{
	return lerp(surfaceColor, FogColor, fogAmount);
}

float get_light_data(float3 lightPosition, float3 worldPosition, float lightRadius)
{
	float4 lightData;
	float3 lightDirection = lightPosition - worldPosition;
	
	lightData.xyz = normalize(lightDirection);
	lightData.w = saturate(1.0f - length(lightDirection) / lightRadius);
	
	return lightData;
}


/*****************************STRUCTS************************/
struct DIRECTION_LIGHT
{
	float4 Direction:DIRECTION;
	float4 Color:COLOR;
	bool Enabled;
};

struct POINT_LIGHT
{
	float4 Position:POSITION;
	float LightRadius;
	float4 Color:COLOR;
	bool Enabled;
};

struct SPOT_LIGHT
{
	
};

struct LIGHT_CONTRIB_DATA
{
	float4 Color:COLOR;
	float3 Normal:NORMAL;
	float3 ViewDirection:DIRECTION;
	float4 LightColor:COLOR;
	float4 LightDirection:DIRECTION;
	float4 SpecularColor:COLOR;
	float SpecularPower;
};

struct DISPLACEMENT_MAP_DATA
{
	float4 Position;
	float3 Normal;
	float4 TextureCoordinate;
	float Scale;
};

float4 get_light_contribution(LIGHT_CONTRIB_DATA IN)
{
	float3 lightDirection = normalize(IN.LightDirection.xyz);
	float n_dot_l = dot(IN.Normal, lightDirection );
	float3 halfVector = normalize(lightDirection + IN.ViewDirection);
	float n_dot_h = dot(IN.Normal,halfVector);
	float4 lightCoefficients = lit(n_dot_l, n_dot_h, IN.SpecularPower);
	float4 diffuse = lightCoefficients.y + IN.Color;
	float4 specular = get_color_contribution(IN.SpecularColor, min(lightCoefficients.z,IN.Color.w));
	
	return (get_color_contribution(IN.LightColor, (diffuse + specular )) * IN.LightDirection.w);
}

float3x3 world_to_tangent_space(float4 tangent,float4 normal,float4x4 world)
{
	float3x3 worldToTangentSpace;
	worldToTangentSpace[0] = mul(tangent, world);
	worldToTangentSpace[1] = mul(cross(tangent,normal), world);
	worldToTangentSpace[2] = mul(normal,world);
	return worldToTangentSpace;
}

float4 get_displaced_position(DISPLACEMENT_MAP_DATA IN, sampler displacementSampler)
{
	float displacementMapScaler = tex2Dlod(displacementSampler, IN.TextureCoordinate).x;
	float4 scaledDisplacementVector = float4(IN.Normal * IN.Scale * displacementMapScaler, 0.0f);
	return IN.Position + scaledDisplacementVector;
}